package com.tenbent.product.base.config.mybatis;

import com.tenbent.product.base.config.datasource.DataSourceConfig;
import com.tenbent.product.base.mybatis.MybatisConfigResource;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;

/**
 * mybatis配置
 *
 * 注意: 在配置mybatis时 因为mybatis-spring集成时类 MapperScannerConfigurer 先于
 *
 * PropertySourcesPlaceholderConfigurer 类被实例化，所以在 MybatisConfig 中使用
 *
 * Environment env 或 @Value 无法获取配置文件的属性。所以只能通过 PropertiesUtils的
 *
 * readProperties方法获取属性。(也可以使用 PropertiesFactoryBean 和 SpEL 表达式来作为替代。)
 *
 * MapperScannerConfigurer Bean可以用 @MapperScan 代替
 *
 * MapperScannerConfigurer 或 @MapperScan 可以只指定basePackage属性，但有限制条件（必须为单一数据源）
 *
 * 如果是多数据源，则必须通过指定 sqlSessionFactoryBeanName 指定。
 *
 * 注意 如果发生baseSqlMapper 注入失败 可能是因为@MapperScan 没有扫描到对应的包。
 *
 * @author Randy
 *
 *         Created by ThinkPad on 2017/7/25.
 */
@Configuration
@MapperScan(value = "com.tenbent.product")
@EnableTransactionManagement
@Import({ DataSourceConfig.class })
public class MybatisConfig {

	private static Logger logger = LoggerFactory.getLogger(MybatisConfig.class);

	@Autowired
	Environment env;

	@Value("${mybatis.scan.package}")
	private String MYBATIS_SCAN_PACKAGE;
	@Value("${mybatis.scan.mapper.package}")
	private String MYBATIS_SCAN_MAPPER_PACKAGE;

	@Value("#{setting['mybatis.scan.package']}")
	private String MYBATIS_SCAN_PACKAGE2;
	@Value("#{setting['mybatis.scan.mapper.package']}")
	private String MYBATIS_SCAN_MAPPER_PACKAGE2;

	// private static final String PROPERTIES_FILE = "mybatis.properties";
	// private static String MYBATIS_SCAN_PACKAGE_TEST;
	// private static String MYBATIS_SCAN_MAPPER_PACKAGE_TEST;

	// static {
	// try {
	// // 此种方式为了配合 MapperScannerConfigurer Bean的basePackage获取属性值的自行实现
	// MYBATIS_SCAN_PACKAGE_TEST =
	// PropertiesUtil.readProperties(PROPERTIES_FILE, "mybatis.scan.package");
	// MYBATIS_SCAN_MAPPER_PACKAGE_TEST =
	// PropertiesUtil.readProperties(PROPERTIES_FILE,
	// "mybatis.scan.mapper.package");
	// } catch (Exception e) {
	// e.printStackTrace();
	// logger.error("read the properties is error,reason : {}", e.getMessage());
	// }
	// }

	@Bean
	public MybatisConfigResource mybatisConfigResource() {
		MybatisConfigResource mybatisConfigResource = new MybatisConfigResource();
		List<String> entityBasePack = new ArrayList<>();
		entityBasePack.add(MYBATIS_SCAN_PACKAGE);
		mybatisConfigResource.setEntityBasePack(entityBasePack);
		List<String> enumBasePack = new ArrayList<>();
		enumBasePack.add(MYBATIS_SCAN_PACKAGE);
		mybatisConfigResource.setEnumBasePack(enumBasePack);
		return mybatisConfigResource;
	}

	@Bean
	public SqlSessionFactory sqlSessionFactory(DataSource ds, MybatisConfigResource mybatisConfig) throws Exception {

		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		sqlSessionFactoryBean.setDataSource(ds);
		sqlSessionFactoryBean.setConfigLocation(mybatisConfig);
		return sqlSessionFactoryBean.getObject();
	}

	@Bean
	public SqlSession sqlSession(SqlSessionFactory sqlSessionFactory) {
		return new SqlSessionTemplate(sqlSessionFactory);
	}

	// 推荐使用@MapperScan(value = "com.tenbent.product.center")代替此@Bean
	// MapperScannerConfigurer Bean 会在容器中第一个启动导致配置文件Properties属性无法获取
	// 如果非要使用@Bean的方式则配置文件属性需要自行实现读取例如使用
	// PropertiesUtil.readProperties(PROPERTIES_FILE, "mybatis.scan.package");
	// @Bean
	// @Conditional(PropertySourcesPlaceholderExitsCondition.class)
	// public MapperScannerConfigurer mapperScannerConfigurer() {
	//
	// MapperScannerConfigurer mapperScannerConfigurer = new
	// MapperScannerConfigurer();
	// // mapperScannerConfigurer.setProcessPropertyPlaceHolders(true);
	// mapperScannerConfigurer.setBasePackage(MYBATIS_SCAN_MAPPER_PACKAGE);
	// // 可以不配置 sqlSessionFactoryBeanName 或 sqlSessionFactory
	// //
	// mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
	// return mapperScannerConfigurer;
	// }

	@Bean
	public DataSourceTransactionManager transactionManager(DataSource ds) {
		DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(ds);
		return transactionManager;
	}
}
